package com.slfx.idgen.demo.idgen.datetime;

import com.slfx.idgen.demo.idgen.snowflake.IdWorker;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

public class DatetimeIdServer {

    private long workerId;

    private long lastTimestamp = -1L;

    private int sequence = 0;

    private int sequenceMask = 1000;

    private String sequenceFormartBits = "%03d";

    private String workerIdFormat = "%04d";

    private final String radix = "10";

    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    public DatetimeIdServer(IdWorker idWorker, int maxSequenceBits) {
        this.workerId = idWorker.initWorkerId();

        if (maxSequenceBits > 0) {
            BigInteger bigInteger = new BigInteger(radix);
            this.sequenceMask = bigInteger.pow(maxSequenceBits).intValue();
            this.sequenceFormartBits = "%0" + maxSequenceBits + "d";
        }

    }

    private String getDatetimeStr() {
        LocalDateTime now = LocalDateTime.now();
        ZonedDateTime zonedDateTime = now.atZone(TimeZone.getDefault().toZoneId());
        return formatter.format(zonedDateTime);
    }

   public synchronized String nextPrefixId(String prefix){
        return prefix+nextId();
   }

    public synchronized String nextId() {

        long timestamp = timeGen();

        //如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一时间生成的，则进行毫秒内序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) % sequenceMask;
            //毫秒内序列溢出
            if (sequence == 0) {
                //阻塞到下一秒,获得新的时间戳
                timestamp = tilNextSecond(lastTimestamp);
            }
        }
        //时间戳改变，毫秒内序列重置
        else {
            sequence = 0;
        }

        //上次生成ID的时间截
        lastTimestamp = timestamp;

        return getDatetimeStr() + String.format(workerIdFormat, workerId) + String.format(sequenceFormartBits, sequence);
    }


    private long tilNextSecond(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis() / 1000;
    }


}
